<?php

class PlatformTT extends PlatformBase
{

    private $updateMoney;

    private $callbackVerify;

    private $payKey;

    private $requestAccessTokenUrl;

    /**
     * @var PlatformTT
     */
    private static $instance;

    /**
     * Get the instance of PlatformTT.
     *
     * @return PlatformTT
     */
    public static function get()
    {
        if (!self::$instance) {
            self::$instance = new PlatformTT();
        }
        return self::$instance;
    }

    private function __construct()
    {
        $this->configs = SzConfig::get()->loadAppConfig(ModuleSns::getSnsConfigFileName(self::PLATFORM_TT), null, true);

        $this->appId = $this->configs['appId']['value'];
        $this->requestUrl = $this->configs['requestUrl']['value'];
        $this->appSecret = $this->configs['appSecret']['value'];
        $this->requestAccessTokenUrl = $this->configs['requestAccessTokenUrl']['value'];
        $this->payKey = $this->configs['payKey']['value'];
        $this->callbackVerify = $this->configs['callbackVerify']['value'];
        $this->updateMoney = [];
    }

    public function getOpenidSessionKey($code)
    {
        $params = array(
            'appid' => $this->appId,
            'secret' => $this->appSecret,
            'code' => $code,
        );
        $url = $this->requestUrl . http_build_query($params, '', '&');

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
        curl_setopt($ch, CURLOPT_HTTPGET, 1); // 发送一个常规的Post请求
        curl_setopt($ch, CURLOPT_HEADER, 0); // 显示返回的Header区域内容
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 5);
        if (substr($url, 0, 5) == 'https') {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        }

        $result = curl_exec($ch);
        if (curl_errno($ch)) {
            //捕抓异常
            echo 'Errno' . curl_error($ch);
            exit;
        }
        curl_close($ch); // 关闭CURL会话

        if (!$result) {
            return array();
        } else {
            $temp = (array)json_decode($result);

            if (isset($temp['errmsg'])) {
                throw new SzException($temp['errcode'], $temp['errmsg']);
            }

            $session_key = str_replace('+', '_ttshine_', $temp['session_key']);
            $session_key = str_replace('=', '_dyshine_', $session_key);
            $redis = SzCacheFactory::get()->getAppCache($temp['openid']);
            $redis->set(GameConst::CACHE_KEY_TT_SESSION_KEY . $temp['openid'], $temp['session_key']);
            $temp['session_key'] = $session_key;
            return $temp;
        }
    }

    /**
     * 验证token
     *
     * @param string $platformId 平台ID
     * @param string $token 登录token
     * @return bool
     * @throws SzException
     */
    public function checkToken($platformId, $token)
    {
        $redis = SzCacheFactory::get()->getAppCache($platformId);

        // 匿名登录验证
        if (stristr($platformId, 'rob_') or stristr($platformId, 'robots_')) {
            $userToken = $redis->get(GameConst::CACHE_KEY_TT_SESSION_KEY . $platformId);

            if (!$userToken) {
                $redis->set(GameConst::CACHE_KEY_TT_SESSION_KEY . $platformId, $token);
            }
            return true;
        }

        $token = str_replace('_ttshine_', '+', $token);
        $token = str_replace('_dyshine_', '=', $token);
        $checkToken = $redis->get(GameConst::CACHE_KEY_TT_SESSION_KEY . $platformId);
        if ($token == $checkToken) {
            return true;
        }
        return false;
    }


    /**
     * 32位整形随机数，放在签名中避免碰撞
     * @return int  32位无符号整形
     */
    private function genRnd()
    {
        return rand(1, GameConst::SQL_INT_LIMITED);
    }


    /**
     * 接口调用凭证
     * @param bool $bRefresh
     * @return mixed|string
     */
    public function getAccessToken($bRefresh = false)
    {
        if (!$bRefresh) {
            $accessToken = SzCacheFactory::get()->getAppCache()->get(GameConst::CACHE_KEY_TT_ACCESS_TOKEN);
            if ($accessToken) {
                return $accessToken;
            }
        }

        $params = [
            'grant_type' => 'client_credential',
            'appid' => $this->appId,
            'secret' => $this->appSecret,
        ];
        $url = $this->requestAccessTokenUrl . SzUtility::buildQueryString($params);

        $try = 5;
        $result = '';
        while (--$try >= 0) {
            try {
                $result = SzUtility::getHttpRequest($url, 20);
                $try = 0;
            } catch (SzException $e) {

            }
        }

        $result = json_decode($result, true);
        error_log('tt_access_token==>' . $result['access_token'] . "\r\n", 3, $_ENV['LOG_ROOT'] . '/payment-' . date('Y-m-d') . '.log');
        SzCacheFactory::get()->getAppCache()->set(GameConst::CACHE_KEY_TT_ACCESS_TOKEN, $result['access_token'], $result['expires_in'] - 1800);
        return $result['access_token'];
    }

    /**
     * 获取支付签名
     * @param $params
     * @param $uri
     * @return string
     */
    public function getSign($params, $uri)
    {
        $paySecret = $this->payKey;
        error_log('tt_paySecret==>' . $paySecret . "\r\n", 3, $_ENV['LOG_ROOT'] . '/payment-' . date('Y-m-d') . '.log');
        ksort($params);
        $temp = http_build_query($params, '', '&');

        $sigString = $temp . '&org_loc=' . $uri . '&method=POST';
        error_log('tt_sigString==>' . $sigString . "\r\n", 3, $_ENV['LOG_ROOT'] . '/payment-' . date('Y-m-d') . '.log');
        $sign = hash_hmac('sha256', $sigString, $paySecret, false);
        error_log('tt_sign==>' . $sign . "\r\n", 3, $_ENV['LOG_ROOT'] . '/payment-' . date('Y-m-d') . '.log');
        return $sign;
    }

    /**
     * http post json 请求
     * @param $url
     * @param $jsonStr
     * @return mixed|null
     */

    public function postHttpRequest($url, $jsonStr)
    {
        $result = null;
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonStr);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
                'Content-Type: application/json; charset=utf-8',
                'Content-Length: ' . strlen($jsonStr)
            )
        );
        $response = curl_exec($ch);
        curl_close($ch);

        $result = json_decode($response, true);
        return $result;
    }

    public function queryPay($orderId, $timeout = 10)
    {
        $access_token = $this->getAccessToken();
        error_log('ttquery_access_token==>' . $access_token . "\r\n", 3, $_ENV['LOG_ROOT'] . '/payment-' . date('Y-m-d') . '.log');
        error_log('ttquery_orderId==>' . $orderId . "\r\n", 3, $_ENV['LOG_ROOT'] . '/payment-' . date('Y-m-d') . '.log');
        $params = array(
            'access_token' => $access_token,
            'orderno' => $orderId,
        );
        $url = $this->callbackVerify . $this->getUrlParams($params);
        error_log('ttquery_url==>' . $url . "\r\n", 3, $_ENV['LOG_ROOT'] . '/payment-' . date('Y-m-d') . '.log');

        list($errno, $errmsg, $response) = $this->httpGet($url, $timeout);
        if ($errno != 0) {
            return array(
                'errno' => $errno,
                'msg' => $errmsg,
                'data' => array()
            );
        }
        return json_decode($response, true);
    }

    private function getUrlParams($params)
    {
        $_data = array();
        foreach ($params as $k => $v) {
            $_data[] = $k . '=' . rawurlencode($v);
        }
        return implode('&', $_data);
    }

    private function httpGet($url, $timeout = 1)
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 0);
        curl_setopt($curl, CURLOPT_AUTOREFERER, 1);
        curl_setopt($curl, CURLOPT_NOSIGNAL, 1);
        if (defined('CURLOPT_CONNECTTIMEOUT_MS')) {
            curl_setopt($curl, CURLOPT_CONNECTTIMEOUT_MS, 1000);
        } else {
            curl_setopt($curl, CURLOPT_TIMEOUT, 1);
        }
        if (defined('CURLOPT_TIMEOUT_MS')) {
            curl_setopt($curl, CURLOPT_TIMEOUT_MS, $timeout * 1000);
        } else {
            curl_setopt($curl, CURLOPT_TIMEOUT, ceil($timeout));
        }
        curl_setopt($curl, CURLOPT_HEADER, 0);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        $errno = 0;
        $errmsg = '';
        $response = curl_exec($curl);

        if ($response === false) {
            $errno = curl_errno($curl);
            $errmsg = curl_error($curl);
        }
        @curl_close($curl);
        return array($errno, $errmsg, $response);
    }
}
